const {exec, spawn, execFile} = require('child_process')
const log4js = require('log4js');
const crypto = require('crypto');
const fs = require('fs')
const rp = require('request-promise-native');
const nodemailer = require('nodemailer');
const config = require('./config');

// 日志
log4js.configure(config.log4js);
const logger = log4js.getLogger('app');

const errMsg = {
  '-99': '未定义的异常'
};

/**
 * 调用 API
 * @param api api.js框架中的值
 * @param json 业务参数
 * @param urlParam url中要替换的值
 * @return {promise}
 */
const callLivy = (api, json, urlParam) => {
  logger.debug('调用api: ', api)
  logger.debug(`url param : ${urlParam}, json=`, json)
  let url = urlParam === undefined || urlParam === null ? api.url : api.url.replace('{}', urlParam)
  let options = Object.assign(api, {
    uri: config.livy.url + url,
    headers: {
      'Content-Type': 'application/json'
    },
    body: json,
    timeout: 60000,
    json: true // Automatically stringifies the body to JSON
  })
  logger.debug(`request options : `, options)
  return rp(options);
}

/**
 * 发送邮件
 * mail: {subject, to, text}
 */
const sendMail = (mail) => {
  if (! mail.to) {
    mail.to = config.mail.to
  }
  logger.debug('send mail: ', mail);
  let transport = nodemailer.createTransport(config.mail, { from: 'antian_369 <antian_369@163.com>' });   //发送邮件的相关参数
  return new Promise((suc, fail) => {
    transport.sendMail(mail, (error, message) => {
      if (error){
        fail(error);
      }else{
        suc(message);
      }
    })
  });
};

/**
 * sleep ms
 */
const sleep = (ms) => {
  return new Promise((suc, fail) => {
    setTimeout(suc, ms)
  })
}

/**
 * HMAC-SHA256
 */
const sha256 = (str) => {
  let secretKey = runModulePro ? config.aliyun_secretKey : config.secretKey
  return crypto.createHmac('sha256', secretKey).update(str).digest('base64');
}

//运行命令
const runExec = (command, options) => {
  logger.info('开始运行命令：' + command, options)
  return new Promise((suc, fail) => {
    exec(command, options, (error, stdout, stderr) => {
      logger.info('命令运行结束：' + command)
      if (error) {
        logger.error(`命令 ${command} 运行异常：`, error)
        fail(error)
      } else {
        suc({ stdout, stderr })
      }
    })
  })
}

//运行shell文件
const runShellFile = (path, args, options) => {
  logger.info(`开始shell文件 ${path} -- [${args}]`, options)
  return new Promise((suc, fail) => {
    execFile(path, args, options, (error, stdout, stderr) => {
      if (error) {
        logger.error(`run shellscript ${path} error: `, error);
        fail(error)
      } else {
        logger.debug(`run ${path} stdout: ${stdout}`)
        logger.debug(`run ${path} stderr: ${stderr}`)
        suc({ stdout, stderr })
      }
    })
  })
}

// 文件是否存在
const exists = (path) => {
  return new Promise ((suc, fail) => {
    fs.access(path, fs.constants.R_OK | fs.constants.W_OK, (err) => {
      suc(!err)
    })
  })
}

module.exports = {
  logger, callLivy, sendMail, sleep, sha256, runExec, runShellFile, exists,
  //返回的异常对象
  getErrMsg: (key) =>{
    if (errMsg[key]){
      return {
        code: key,
        msg: errMsg[key]
      }
    }else{
      return {
        code: '-99',
        msg: errMsg['-99']
      }
    }
  },
  sucResMsg: {
    code: '0',
    msg: '成功'
  }
}

Date.prototype.format = function(formatStr)
{
    var str = formatStr;
    var Week = ['日', '一', '二', '三', '四', '五', '六'];

    str = str.replace(/yyyy|YYYY/, this.getFullYear());
    str = str.replace(/yy|YY/, (this.getYear() % 100) > 9 ? (this.getYear() % 100).toString() : '0' + (this.getYear() % 100));

    var month = this.getMonth() + 1;
    str = str.replace(/MM/, month > 9 ? month.toString() : '0' + month);
    str = str.replace(/M/g, month);

    str = str.replace(/w|W/g, Week[this.getDay()]);

    str = str.replace(/dd|DD/, this.getDate() > 9 ? this.getDate().toString() : '0' + this.getDate());
    str = str.replace(/d|D/g, this.getDate());

    str = str.replace(/hh|HH/, this.getHours() > 9 ? this.getHours().toString() : '0' + this.getHours());
    str = str.replace(/h|H/g, this.getHours());
    str = str.replace(/mm/, this.getMinutes() > 9 ? this.getMinutes().toString() : '0' + this.getMinutes());
    str = str.replace(/m/g, this.getMinutes());

    str = str.replace(/ss|SS/, this.getSeconds() > 9 ? this.getSeconds().toString() : '0' + this.getSeconds());
    str = str.replace(/s|S/g, this.getSeconds());

    return str;
};

Date.prototype.UTCFormat = function(formatStr)
{
    var str = formatStr;
    var Week = ['日', '一', '二', '三', '四', '五', '六'];

    str = str.replace(/yyyy|YYYY/, this.getUTCFullYear());

    var month = this.getUTCMonth() + 1;
    str = str.replace(/MM/, month > 9 ? month.toString() : '0' + month);
    str = str.replace(/M/g, month);

    str = str.replace(/w|W/g, Week[this.getUTCDay()]);

    str = str.replace(/dd|DD/, this.getUTCDate() > 9 ? this.getUTCDate().toString() : '0' + this.getUTCDate());
    str = str.replace(/d|D/g, this.getUTCDate());

    str = str.replace(/hh|HH/, this.getUTCHours() > 9 ? this.getUTCHours().toString() : '0' + this.getUTCHours());
    str = str.replace(/h|H/g, this.getUTCHours());
    str = str.replace(/mm/, this.getUTCMinutes() > 9 ? this.getUTCMinutes().toString() : '0' + this.getUTCMinutes());
    str = str.replace(/m/g, this.getUTCMinutes());

    str = str.replace(/ss|SS/, this.getUTCSeconds() > 9 ? this.getUTCSeconds().toString() : '0' + this.getUTCSeconds());
    str = str.replace(/s|S/g, this.getUTCSeconds());

    return str;
};